Quick overview

Current status

#library(nCov2019)
library(leaflet)
library(dplyr)
library(ggplot2)
library(plotly)
library(scales)
library(xts)
library(dygraphs)
library(corrplot)
COVID<-read.csv("covid_19_data.csv")
COVID_2<-read.csv("COVID19_9-Apr.csv")

Format date:

Date<-as.Date(COVID_2$Date, format="%m/%d/%y") 

COVID_2$Date2<-Date
COVID_updated<-COVID_2 %>% filter(Date2==max(Date2))
leaflet(width = "100%") %>% 
  addProviderTiles("CartoDB.DarkMatter") %>% 
  setView(lng = 0, lat = 10, zoom = 1.5) %>% 
  addCircleMarkers(data = COVID_updated, 
                   lng = ~ Long,
                   lat = ~ Lat,
                   radius = ~ log(Confirmed+1),
                   color = rgb(218/255,65/255,56/255),
                   fillOpacity = ~ ifelse(Confirmed > 0, 1, 0),
                   stroke = FALSE,
                   label = ~ paste(Province.State,",",Country.Region, ": ", Confirmed)
                   )

Current top 10 countries:

COVID_top<-COVID_2 %>% filter(Date2==max(Date2)) %>% 
  group_by(Country.Region) %>% summarise(Total_confirmed=sum(Confirmed)) %>% 
  top_n(10,Total_confirmed) %>% arrange(desc(Total_confirmed))
plot<-ggplot(data=COVID_top
       , aes(x=Total_confirmed,y=reorder(Country.Region,Total_confirmed))) +
  geom_bar(stat ="identity",alpha=0.8,fill="firebrick3") +
  geom_text(aes(label=Total_confirmed), vjust=0.5, hjust=0.9,color="black", size=3.5) +
  scale_x_continuous(labels = comma) +
  labs(title = paste("Top 10 countries with confirmed cases as of ",max(COVID_2$Date2)),
       x = "Confirmed cases",
       y = "Country") +
  theme_minimal()

ggplotly(plot,tooltip = c("x"),width=750)

Time distribution:

COVID_2_Day<- COVID_2 %>% group_by(Date2) %>% summarise(World_confirmed=sum(Confirmed),
                                                        World_deaths=sum(Deaths),
                                                        World_recovered=sum(Recovered))


COVID_Day_confirmed_series<-xts(COVID_2_Day$World_confirmed, order.by=COVID_2_Day$Date2)
COVID_Day_deaths_series<-xts(COVID_2_Day$World_deaths, order.by=COVID_2_Day$Date2)
COVID_Day_recovered_series<-xts(COVID_2_Day$World_recovered, order.by=COVID_2_Day$Date2)

Day_summary<-cbind(COVID_Day_confirmed_series,COVID_Day_deaths_series,COVID_Day_recovered_series)
dygraph(Day_summary, main = "SARS-COV2-outbreak: Total worldwide cases", 
        xlab="Date", ylab="Total cases",width = 750) %>% 
  dySeries("COVID_Day_confirmed_series", "Total cases",drawPoints = TRUE, 
           pointSize = 3, color=rgb(53/255,116/255,199/255)) %>% 
  dySeries("COVID_Day_deaths_series", "Total deaths",drawPoints = TRUE, 
           pointSize = 3, color=rgb(189/255,55/255,48/255)) %>% 
  dySeries("COVID_Day_recovered_series", "Total recovered",drawPoints = TRUE, 
           pointSize = 3, color=rgb(69/255,136/255,51/255)) %>% 
  dyRangeSelector()
New_count<-function(x)
{
  Daily_cases<-numeric(length(x))
  
  for(i in length(x):2)
  {
    Daily_cases[i]=x[i] - x[i-1]
  }
  return(Daily_cases)
}

New_cases<-New_count(COVID_2_Day$World_confirmed)
New_deaths<-New_count(COVID_2_Day$World_deaths)
New_recovered<-New_count(COVID_2_Day$World_recovered)
COVID_New_confirmed_series<-xts(New_cases, order.by=COVID_2_Day$Date2)
COVID_New_deaths_series<-xts(New_deaths, order.by=COVID_2_Day$Date2)
COVID_New_recovered_series<-xts(New_recovered, order.by=COVID_2_Day$Date2)

New_summary<-cbind(COVID_New_confirmed_series,COVID_New_deaths_series,COVID_New_recovered_series)
dygraph(New_summary, main = "SARS-COV2-outbreak: Total worldwide cases", 
        xlab="Date", ylab="Novel coronavirus cases",width = 750) %>% 
  dySeries("COVID_New_confirmed_series", "New cases",drawPoints = TRUE, 
           pointSize = 3, color=rgb(53/255,116/255,199/255)) %>% 
  dySeries("COVID_New_deaths_series", "New deaths",drawPoints = TRUE, 
           pointSize = 3, color=rgb(189/255,55/255,48/255)) %>% 
  dySeries("COVID_New_recovered_series", "New recovered",drawPoints = TRUE, 
           pointSize = 3, color=rgb(69/255,136/255,51/255)) %>% 
  dyRangeSelector()

Team members countries total cases:

COVID_2_Day_Lebanon<- COVID_2 %>% 
  filter(Country.Region %in% c("Lebanon")) %>% 
  group_by(Date2) %>% summarise(World_confirmed=sum(Confirmed))

COVID_2_Day_Chile<- COVID_2 %>% 
  filter(Country.Region %in% c("Chile")) %>% 
  group_by(Date2) %>% summarise(World_confirmed=sum(Confirmed))

COVID_2_Day_Colombia<- COVID_2 %>% 
  filter(Country.Region %in% c("Colombia")) %>% 
  group_by(Date2) %>% summarise(World_confirmed=sum(Confirmed))

COVID_2_Day_CostaRica<- COVID_2 %>% 
  filter(Country.Region %in% c("Costa Rica")) %>% 
  group_by(Date2) %>% summarise(World_confirmed=sum(Confirmed))


COVID_Day_series_Lebanon<-xts(COVID_2_Day_Lebanon$World_confirmed, order.by=COVID_2_Day_Lebanon$Date2)
COVID_Day_series_Chile<-xts(COVID_2_Day_Chile$World_confirmed, order.by=COVID_2_Day_Chile$Date2)
COVID_Day_series_Colombia<-xts(COVID_2_Day_Colombia$World_confirmed, order.by=COVID_2_Day_Colombia$Date2)
COVID_Day_series_CostaRica<-xts(COVID_2_Day_CostaRica$World_confirmed, order.by=COVID_2_Day_CostaRica$Date2)

Our_Countries<-cbind(COVID_Day_series_Lebanon,COVID_Day_series_Chile,COVID_Day_series_Colombia,COVID_Day_series_CostaRica)
dygraph(Our_Countries, main = "SARS-COV2-outbreak: Total cases by country", xlab="Date", ylab="Total cases",width = 750) %>% 
  dySeries("COVID_Day_series_Lebanon", "Lebanon",drawPoints = TRUE, 
           pointSize = 3, color=rgb(0,0,3/255)) %>% 
  dySeries("COVID_Day_series_Chile", "Chile",drawPoints = TRUE, 
           pointSize = 3,color=rgb(120/255,28/255,109/255)) %>% 
  dySeries("COVID_Day_series_Colombia", "Colombia",drawPoints = TRUE, 
           pointSize = 3,color=rgb(237/255,105/255,37/255)) %>% 
  dySeries("COVID_Day_series_CostaRica", "Costa Rica",drawPoints = TRUE,
           pointSize = 3,color=rgb(204/255,197/255,126/255)) %>% 
  dyRangeSelector()
New_Lebanon<-New_count(COVID_2_Day_Lebanon$World_confirmed)
New_Chile<-New_count(COVID_2_Day_Chile$World_confirmed)
New_Colombia<-New_count(COVID_2_Day_Colombia$World_confirmed)
New_CostaRica<-New_count(COVID_2_Day_CostaRica$World_confirmed)

COVID_New_series_Lebanon<-xts(New_Lebanon, order.by=COVID_2_Day_Lebanon$Date2)
COVID_New_series_Chile<-xts(New_Chile, order.by=COVID_2_Day_Chile$Date2)
COVID_New_series_Colombia<-xts(New_Colombia, order.by=COVID_2_Day_Colombia$Date2)
COVID_New_series_CostaRica<-xts(New_CostaRica, order.by=COVID_2_Day_CostaRica$Date2)

Our_New_Countries<-cbind(COVID_New_series_Lebanon,COVID_New_series_Chile,COVID_New_series_Colombia,COVID_New_series_CostaRica)
dygraph(Our_New_Countries, main = "SARS-COV2-outbreak: New cases by country", xlab="Date", ylab="Total cases",width = 750) %>% 
  dySeries("COVID_New_series_Lebanon", "Lebanon",drawPoints = TRUE, 
           pointSize = 3, color=rgb(0,0,3/255)) %>% 
  dySeries("COVID_New_series_Chile", "Chile",drawPoints = TRUE, 
           pointSize = 3,color=rgb(120/255,28/255,109/255)) %>% 
  dySeries("COVID_New_series_Colombia", "Colombia",drawPoints = TRUE, 
           pointSize = 3,color=rgb(237/255,105/255,37/255)) %>% 
  dySeries("COVID_New_series_CostaRica", "Costa Rica",drawPoints = TRUE,
           pointSize = 3,color=rgb(204/255,197/255,126/255)) %>% 
  dyRangeSelector()

Looking for correlations

fig <- plot_ly(COVID_updated, x = ~Confirmed, y = ~Deaths, z = ~Recovered, width=750) %>% 
  add_markers(text= ~Country.Region ,hoverinfo= "text",
              marker = list(color=rgb(189/255,55/255,48/255))) %>% 
  layout(title="Confirmed cases Vs. Deaths Vs. Recovered", scene = list(
                    xaxis = list(title = 'Confirmed'),
                     yaxis = list(title = 'Deaths'),
                     zaxis = list(title = 'Recovered'))) 
fig

Human Development Index

HDI<-read.csv("Human Development Index (HDI)_2.csv",sep=";",dec=",")
COVID_Country<-COVID_2 %>% filter(Date2==max(Date2)) %>% 
  group_by(Country.Region) %>% summarise(Total_confirmed=sum(Confirmed),
                                         Total_deaths=sum(Deaths),
                                         Total_Recovered=sum(Recovered))

Remove after parentheses:

HDI$Country_2<-gsub("\\s*\\([^\\)]+\\)","",as.character(HDI$Country))
HDI$Country_2[HDI$Country_2=="United States"]<-"US"
HDI$Country_2[HDI$Country_2=="Korea"]<-"South Korea"

Population:

Population<-read.csv("World_population.csv",sep=";",dec=",")

Remove after commma:

Population$Country_Name_2<-gsub(",.*", "", as.character(Population$Country_Name))
Population$Country_Name_2[Population$Country_Name_2=="United States"]<-"US"
Population$Country_Name_2[Population$Country_Code=="KOR"]<-"South Korea"
Population$Country_Name_2[Population$Country_Code=="CZE"]<-"Czechia"

Natural Join:

COVID_3<- COVID_Country %>% inner_join(HDI,by=c("Country.Region"="Country_2")) %>% 
  inner_join(Population,by=c("Country.Region"="Country_Name_2")) %>% 
  select(Country.Region,Total_confirmed,Total_deaths,Total_Recovered,HDI_Rank_2018,Year_2018,
         Country_Code,Population_2018) %>% 
  mutate(Cases_million=(Total_confirmed/Population_2018)*1000000,
         Recovered_percentage=(Total_Recovered/Total_confirmed)*100)  

COVID_3<-COVID_3[!is.na(COVID_3$Population_2018),]

Plot the Human Development Index(HDI) Vs. the number of cases (applying a log transformation), and the proportion of recovered cases:

plot<-ggplot(data=COVID_3,aes(x=log(Cases_million),y=Year_2018,
                        size=Recovered_percentage,text=Country.Region)) +
  geom_point(color="black",fill=rgb(237/255,105/255,37/255),shape=21,alpha=0.6) +
  scale_size(range = c(3,15), name="Recovered \n percentage") +
  theme_minimal() + 
  theme(legend.position="bottom") +
  labs(title="HDI Vs. logarithmus of COVID-19 cases by million inhabitants \n and proportion of recovered",
       x="ln(Cases/1M population)",
       y="HDI")

ggplotly(plot,tooltip = c("text"),width=750)
COVID_numeric_1<-COVID_3 %>% mutate(Log_cases=log(Cases_million),
                                    Death_percentage=(Total_deaths/Total_confirmed)*100) %>% 
  select(Log_cases,Recovered_percentage,Death_percentage,Year_2018)

corrplot(cor(COVID_numeric_1),method = "number",tl.col="black",tl.srt=15,
         col=colorRampPalette(c(rgb(204/255,197/255,126/255),rgb(237/255,105/255,37/255)))(200))

Infants lacking immunization, measles (% of one-year-olds)

Measles<-read.csv("Measles_immunization.csv",sep=";",dec=".")
Measles$Country_2<-gsub("\\s*\\([^\\)]+\\)","",as.character(Measles$Country))
Measles$Country_2[Measles$Country_2=="United States"]<-"US"
Measles$Country_2[Measles$Country_2=="Korea"]<-"South Korea"
COVID_3<- COVID_3 %>% inner_join(Measles,by=c("Country.Region"="Country_2")) %>% select(-c("Country"))
ggplot(COVID_3, aes(y=Measles_2018)) + 
  geom_boxplot(fill="dodgerblue4",outlier.shape = 21, 
               outlier.fill = "firebrick",alpha=0.75) +
  ggtitle("Boxplot of % infants lacking measles immunization") + ylab("% of infants") +
  theme_minimal()

ggplot(COVID_3, aes(Measles_2018)) + 
  geom_histogram(fill="dodgerblue4",bins=20,alpha=0.8) +
  ggtitle("Histogram of % infants lacking measles immunization") + 
  xlab("% of infants") + 
  ylab("Count") +
  theme_minimal()

plot<-ggplot(data=COVID_3,aes(x=log(Cases_million),y=Measles_2018,
                        size=Recovered_percentage,text=Country.Region)) +
  geom_point(color="black",fill=rgb(120/255,28/255,109/255),shape=21,alpha=0.6) +
  scale_size(range = c(3,15), name="Recovered \n percentage") +
  theme_minimal() + 
  theme(legend.position="bottom") +
  labs(title="% infants lacking measles immunization Vs. logarithmus of COVID-19 cases by million inhabitants \n and proportion of recovered",
       x="ln(Cases/1M population)",
       y="% of infants")

ggplotly(plot,tooltip = c("text"),width=750)

Health expenditure (% of GDP)

Health_expenditure<-read.csv("Health_expenditure_GDP.csv",sep=";",dec=".")
Health_expenditure$Country_2<-gsub("\\s*\\([^\\)]+\\)","",
                                   as.character(Health_expenditure$Country))
Health_expenditure$Country_2[Health_expenditure$Country_2=="United States"]<-"US"
Health_expenditure$Country_2[Health_expenditure$Country_2=="Korea"]<-"South Korea"
COVID_3<- COVID_3 %>% inner_join(Health_expenditure,by=c("Country.Region"="Country_2")) %>% select(-c("Country"))

#write.csv(COVID_3,"COVID_Covariables.csv")
plot<-ggplot(data=COVID_3,aes(x=log(Cases_million),y=Expenditure_2016,
                        size=Recovered_percentage,text=Country.Region)) +
  geom_point(color="black",fill=rgb(204/255,197/255,126/255),shape=21,alpha=0.6) +
  scale_size(range = c(3,15), name="Recovered \n percentage") +
  theme_minimal() + 
  theme(legend.position="bottom") +
  labs(title="Health expenditure (% of GDP) Vs. logarithmus of COVID-19 cases by million inhabitants \n and proportion of recovered",
       x="ln(Cases/1M population)",
       y="% of GDP in health")

ggplotly(plot,tooltip = c("text"),width=750)

Fitting a regression model

Mod1<-lm(log(COVID_3$Cases_million)~COVID_3$Year_2018+COVID_3$Measles_2018+COVID_3$Expenditure_2016)
summary(Mod1)

Call:
lm(formula = log(COVID_3$Cases_million) ~ COVID_3$Year_2018 + 
    COVID_3$Measles_2018 + COVID_3$Expenditure_2016)

Residuals:
    Min      1Q  Median      3Q     Max 
-3.2198 -0.7662 -0.0500  0.8155  4.4182 

Coefficients:
                          Estimate Std. Error t value Pr(>|t|)    
(Intercept)              -6.560366   0.669104  -9.805   <2e-16 ***
COVID_3$Year_2018        13.214572   0.846290  15.615   <2e-16 ***
COVID_3$Measles_2018      0.010114   0.009523   1.062   0.2899    
COVID_3$Expenditure_2016  0.116171   0.042407   2.739   0.0069 ** 
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 1.282 on 151 degrees of freedom
Multiple R-squared:  0.7261,    Adjusted R-squared:  0.7206 
F-statistic: 133.4 on 3 and 151 DF,  p-value: < 2.2e-16
hist(Mod1$residuals)

shapiro.test(Mod1$residuals)

    Shapiro-Wilk normality test

data:  Mod1$residuals
W = 0.98744, p-value = 0.1775
LS0tCnRpdGxlOiAiQ09WSUQtMTkgT3V0YnJlYWs6IFdvcmxkd2lkZSBhbmFseXNpcyIKYXV0aG9yOiAiQW91biwgQ2FtYXJnbywgTWFydGluZXosUm9kcmlndWV6IgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICAgIHRvY19kZXB0aDogMwogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IHRydWUKICAgICAgc21vb3RoX3Njcm9sbDogdHJ1ZQogICAgdGhlbWU6IGNvc21vCiAgICAgCi0tLQohW10oQ29yb25hdmlydXMuanBnKQoKIyBRdWljayBvdmVydmlldwoKIyMgQ3VycmVudCBzdGF0dXMKCgpgYGB7cixtZXNzYWdlPUZBTFNFLHdhcm5pbmc9RkFMU0V9CiNsaWJyYXJ5KG5Db3YyMDE5KQpsaWJyYXJ5KGxlYWZsZXQpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShwbG90bHkpCmxpYnJhcnkoc2NhbGVzKQpsaWJyYXJ5KHh0cykKbGlicmFyeShkeWdyYXBocykKbGlicmFyeShjb3JycGxvdCkKYGBgCgpgYGB7cn0KQ09WSUQ8LXJlYWQuY3N2KCJjb3ZpZF8xOV9kYXRhLmNzdiIpCkNPVklEXzI8LXJlYWQuY3N2KCJDT1ZJRDE5XzktQXByLmNzdiIpCmBgYAoKRm9ybWF0IGRhdGU6CmBgYHtyfQpEYXRlPC1hcy5EYXRlKENPVklEXzIkRGF0ZSwgZm9ybWF0PSIlbS8lZC8leSIpIAoKQ09WSURfMiREYXRlMjwtRGF0ZQpgYGAKCmBgYHtyfQpDT1ZJRF91cGRhdGVkPC1DT1ZJRF8yICU+JSBmaWx0ZXIoRGF0ZTI9PW1heChEYXRlMikpCmBgYAoKYGBge3Isd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFfQpsZWFmbGV0KHdpZHRoID0gIjEwMCUiKSAlPiUgCiAgYWRkUHJvdmlkZXJUaWxlcygiQ2FydG9EQi5EYXJrTWF0dGVyIikgJT4lIAogIHNldFZpZXcobG5nID0gMCwgbGF0ID0gMTAsIHpvb20gPSAxLjUpICU+JSAKICBhZGRDaXJjbGVNYXJrZXJzKGRhdGEgPSBDT1ZJRF91cGRhdGVkLCAKICAgICAgICAgICAgICAgICAgIGxuZyA9IH4gTG9uZywKICAgICAgICAgICAgICAgICAgIGxhdCA9IH4gTGF0LAogICAgICAgICAgICAgICAgICAgcmFkaXVzID0gfiBsb2coQ29uZmlybWVkKzEpLAogICAgICAgICAgICAgICAgICAgY29sb3IgPSByZ2IoMjE4LzI1NSw2NS8yNTUsNTYvMjU1KSwKICAgICAgICAgICAgICAgICAgIGZpbGxPcGFjaXR5ID0gfiBpZmVsc2UoQ29uZmlybWVkID4gMCwgMSwgMCksCiAgICAgICAgICAgICAgICAgICBzdHJva2UgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgIGxhYmVsID0gfiBwYXN0ZShQcm92aW5jZS5TdGF0ZSwiLCIsQ291bnRyeS5SZWdpb24sICI6ICIsIENvbmZpcm1lZCkKICAgICAgICAgICAgICAgICAgICkKYGBgCgpDdXJyZW50IHRvcCAxMCBjb3VudHJpZXM6CmBgYHtyfQpDT1ZJRF90b3A8LUNPVklEXzIgJT4lIGZpbHRlcihEYXRlMj09bWF4KERhdGUyKSkgJT4lIAogIGdyb3VwX2J5KENvdW50cnkuUmVnaW9uKSAlPiUgc3VtbWFyaXNlKFRvdGFsX2NvbmZpcm1lZD1zdW0oQ29uZmlybWVkKSkgJT4lIAogIHRvcF9uKDEwLFRvdGFsX2NvbmZpcm1lZCkgJT4lIGFycmFuZ2UoZGVzYyhUb3RhbF9jb25maXJtZWQpKQpgYGAKCmBgYHtyfQpwbG90PC1nZ3Bsb3QoZGF0YT1DT1ZJRF90b3AKICAgICAgICwgYWVzKHg9VG90YWxfY29uZmlybWVkLHk9cmVvcmRlcihDb3VudHJ5LlJlZ2lvbixUb3RhbF9jb25maXJtZWQpKSkgKwogIGdlb21fYmFyKHN0YXQgPSJpZGVudGl0eSIsYWxwaGE9MC44LGZpbGw9ImZpcmVicmljazMiKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbD1Ub3RhbF9jb25maXJtZWQpLCB2anVzdD0wLjUsIGhqdXN0PTAuOSxjb2xvcj0iYmxhY2siLCBzaXplPTMuNSkgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBjb21tYSkgKwogIGxhYnModGl0bGUgPSBwYXN0ZSgiVG9wIDEwIGNvdW50cmllcyB3aXRoIGNvbmZpcm1lZCBjYXNlcyBhcyBvZiAiLG1heChDT1ZJRF8yJERhdGUyKSksCiAgICAgICB4ID0gIkNvbmZpcm1lZCBjYXNlcyIsCiAgICAgICB5ID0gIkNvdW50cnkiKSArCiAgdGhlbWVfbWluaW1hbCgpCgpnZ3Bsb3RseShwbG90LHRvb2x0aXAgPSBjKCJ4Iiksd2lkdGg9NzUwKQpgYGAKClRpbWUgZGlzdHJpYnV0aW9uOgpgYGB7cn0KQ09WSURfMl9EYXk8LSBDT1ZJRF8yICU+JSBncm91cF9ieShEYXRlMikgJT4lIHN1bW1hcmlzZShXb3JsZF9jb25maXJtZWQ9c3VtKENvbmZpcm1lZCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgV29ybGRfZGVhdGhzPXN1bShEZWF0aHMpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFdvcmxkX3JlY292ZXJlZD1zdW0oUmVjb3ZlcmVkKSkKCgpDT1ZJRF9EYXlfY29uZmlybWVkX3NlcmllczwteHRzKENPVklEXzJfRGF5JFdvcmxkX2NvbmZpcm1lZCwgb3JkZXIuYnk9Q09WSURfMl9EYXkkRGF0ZTIpCkNPVklEX0RheV9kZWF0aHNfc2VyaWVzPC14dHMoQ09WSURfMl9EYXkkV29ybGRfZGVhdGhzLCBvcmRlci5ieT1DT1ZJRF8yX0RheSREYXRlMikKQ09WSURfRGF5X3JlY292ZXJlZF9zZXJpZXM8LXh0cyhDT1ZJRF8yX0RheSRXb3JsZF9yZWNvdmVyZWQsIG9yZGVyLmJ5PUNPVklEXzJfRGF5JERhdGUyKQoKRGF5X3N1bW1hcnk8LWNiaW5kKENPVklEX0RheV9jb25maXJtZWRfc2VyaWVzLENPVklEX0RheV9kZWF0aHNfc2VyaWVzLENPVklEX0RheV9yZWNvdmVyZWRfc2VyaWVzKQpgYGAKCmBgYHtyfQpkeWdyYXBoKERheV9zdW1tYXJ5LCBtYWluID0gIlNBUlMtQ09WMi1vdXRicmVhazogVG90YWwgd29ybGR3aWRlIGNhc2VzIiwgCiAgICAgICAgeGxhYj0iRGF0ZSIsIHlsYWI9IlRvdGFsIGNhc2VzIix3aWR0aCA9IDc1MCkgJT4lIAogIGR5U2VyaWVzKCJDT1ZJRF9EYXlfY29uZmlybWVkX3NlcmllcyIsICJUb3RhbCBjYXNlcyIsZHJhd1BvaW50cyA9IFRSVUUsIAogICAgICAgICAgIHBvaW50U2l6ZSA9IDMsIGNvbG9yPXJnYig1My8yNTUsMTE2LzI1NSwxOTkvMjU1KSkgJT4lIAogIGR5U2VyaWVzKCJDT1ZJRF9EYXlfZGVhdGhzX3NlcmllcyIsICJUb3RhbCBkZWF0aHMiLGRyYXdQb2ludHMgPSBUUlVFLCAKICAgICAgICAgICBwb2ludFNpemUgPSAzLCBjb2xvcj1yZ2IoMTg5LzI1NSw1NS8yNTUsNDgvMjU1KSkgJT4lIAogIGR5U2VyaWVzKCJDT1ZJRF9EYXlfcmVjb3ZlcmVkX3NlcmllcyIsICJUb3RhbCByZWNvdmVyZWQiLGRyYXdQb2ludHMgPSBUUlVFLCAKICAgICAgICAgICBwb2ludFNpemUgPSAzLCBjb2xvcj1yZ2IoNjkvMjU1LDEzNi8yNTUsNTEvMjU1KSkgJT4lIAogIGR5UmFuZ2VTZWxlY3RvcigpCmBgYAoKCmBgYHtyfQpOZXdfY291bnQ8LWZ1bmN0aW9uKHgpCnsKICBEYWlseV9jYXNlczwtbnVtZXJpYyhsZW5ndGgoeCkpCiAgCiAgZm9yKGkgaW4gbGVuZ3RoKHgpOjIpCiAgewogICAgRGFpbHlfY2FzZXNbaV09eFtpXSAtIHhbaS0xXQogIH0KICByZXR1cm4oRGFpbHlfY2FzZXMpCn0KCk5ld19jYXNlczwtTmV3X2NvdW50KENPVklEXzJfRGF5JFdvcmxkX2NvbmZpcm1lZCkKTmV3X2RlYXRoczwtTmV3X2NvdW50KENPVklEXzJfRGF5JFdvcmxkX2RlYXRocykKTmV3X3JlY292ZXJlZDwtTmV3X2NvdW50KENPVklEXzJfRGF5JFdvcmxkX3JlY292ZXJlZCkKQ09WSURfTmV3X2NvbmZpcm1lZF9zZXJpZXM8LXh0cyhOZXdfY2FzZXMsIG9yZGVyLmJ5PUNPVklEXzJfRGF5JERhdGUyKQpDT1ZJRF9OZXdfZGVhdGhzX3NlcmllczwteHRzKE5ld19kZWF0aHMsIG9yZGVyLmJ5PUNPVklEXzJfRGF5JERhdGUyKQpDT1ZJRF9OZXdfcmVjb3ZlcmVkX3NlcmllczwteHRzKE5ld19yZWNvdmVyZWQsIG9yZGVyLmJ5PUNPVklEXzJfRGF5JERhdGUyKQoKTmV3X3N1bW1hcnk8LWNiaW5kKENPVklEX05ld19jb25maXJtZWRfc2VyaWVzLENPVklEX05ld19kZWF0aHNfc2VyaWVzLENPVklEX05ld19yZWNvdmVyZWRfc2VyaWVzKQpgYGAKCmBgYHtyfQpkeWdyYXBoKE5ld19zdW1tYXJ5LCBtYWluID0gIlNBUlMtQ09WMi1vdXRicmVhazogVG90YWwgd29ybGR3aWRlIGNhc2VzIiwgCiAgICAgICAgeGxhYj0iRGF0ZSIsIHlsYWI9Ik5vdmVsIGNvcm9uYXZpcnVzIGNhc2VzIix3aWR0aCA9IDc1MCkgJT4lIAogIGR5U2VyaWVzKCJDT1ZJRF9OZXdfY29uZmlybWVkX3NlcmllcyIsICJOZXcgY2FzZXMiLGRyYXdQb2ludHMgPSBUUlVFLCAKICAgICAgICAgICBwb2ludFNpemUgPSAzLCBjb2xvcj1yZ2IoNTMvMjU1LDExNi8yNTUsMTk5LzI1NSkpICU+JSAKICBkeVNlcmllcygiQ09WSURfTmV3X2RlYXRoc19zZXJpZXMiLCAiTmV3IGRlYXRocyIsZHJhd1BvaW50cyA9IFRSVUUsIAogICAgICAgICAgIHBvaW50U2l6ZSA9IDMsIGNvbG9yPXJnYigxODkvMjU1LDU1LzI1NSw0OC8yNTUpKSAlPiUgCiAgZHlTZXJpZXMoIkNPVklEX05ld19yZWNvdmVyZWRfc2VyaWVzIiwgIk5ldyByZWNvdmVyZWQiLGRyYXdQb2ludHMgPSBUUlVFLCAKICAgICAgICAgICBwb2ludFNpemUgPSAzLCBjb2xvcj1yZ2IoNjkvMjU1LDEzNi8yNTUsNTEvMjU1KSkgJT4lIAogIGR5UmFuZ2VTZWxlY3RvcigpCmBgYAoKClRlYW0gbWVtYmVycyBjb3VudHJpZXMgdG90YWwgY2FzZXM6CmBgYHtyfQpDT1ZJRF8yX0RheV9MZWJhbm9uPC0gQ09WSURfMiAlPiUgCiAgZmlsdGVyKENvdW50cnkuUmVnaW9uICVpbiUgYygiTGViYW5vbiIpKSAlPiUgCiAgZ3JvdXBfYnkoRGF0ZTIpICU+JSBzdW1tYXJpc2UoV29ybGRfY29uZmlybWVkPXN1bShDb25maXJtZWQpKQoKQ09WSURfMl9EYXlfQ2hpbGU8LSBDT1ZJRF8yICU+JSAKICBmaWx0ZXIoQ291bnRyeS5SZWdpb24gJWluJSBjKCJDaGlsZSIpKSAlPiUgCiAgZ3JvdXBfYnkoRGF0ZTIpICU+JSBzdW1tYXJpc2UoV29ybGRfY29uZmlybWVkPXN1bShDb25maXJtZWQpKQoKQ09WSURfMl9EYXlfQ29sb21iaWE8LSBDT1ZJRF8yICU+JSAKICBmaWx0ZXIoQ291bnRyeS5SZWdpb24gJWluJSBjKCJDb2xvbWJpYSIpKSAlPiUgCiAgZ3JvdXBfYnkoRGF0ZTIpICU+JSBzdW1tYXJpc2UoV29ybGRfY29uZmlybWVkPXN1bShDb25maXJtZWQpKQoKQ09WSURfMl9EYXlfQ29zdGFSaWNhPC0gQ09WSURfMiAlPiUgCiAgZmlsdGVyKENvdW50cnkuUmVnaW9uICVpbiUgYygiQ29zdGEgUmljYSIpKSAlPiUgCiAgZ3JvdXBfYnkoRGF0ZTIpICU+JSBzdW1tYXJpc2UoV29ybGRfY29uZmlybWVkPXN1bShDb25maXJtZWQpKQoKCkNPVklEX0RheV9zZXJpZXNfTGViYW5vbjwteHRzKENPVklEXzJfRGF5X0xlYmFub24kV29ybGRfY29uZmlybWVkLCBvcmRlci5ieT1DT1ZJRF8yX0RheV9MZWJhbm9uJERhdGUyKQpDT1ZJRF9EYXlfc2VyaWVzX0NoaWxlPC14dHMoQ09WSURfMl9EYXlfQ2hpbGUkV29ybGRfY29uZmlybWVkLCBvcmRlci5ieT1DT1ZJRF8yX0RheV9DaGlsZSREYXRlMikKQ09WSURfRGF5X3Nlcmllc19Db2xvbWJpYTwteHRzKENPVklEXzJfRGF5X0NvbG9tYmlhJFdvcmxkX2NvbmZpcm1lZCwgb3JkZXIuYnk9Q09WSURfMl9EYXlfQ29sb21iaWEkRGF0ZTIpCkNPVklEX0RheV9zZXJpZXNfQ29zdGFSaWNhPC14dHMoQ09WSURfMl9EYXlfQ29zdGFSaWNhJFdvcmxkX2NvbmZpcm1lZCwgb3JkZXIuYnk9Q09WSURfMl9EYXlfQ29zdGFSaWNhJERhdGUyKQoKT3VyX0NvdW50cmllczwtY2JpbmQoQ09WSURfRGF5X3Nlcmllc19MZWJhbm9uLENPVklEX0RheV9zZXJpZXNfQ2hpbGUsQ09WSURfRGF5X3Nlcmllc19Db2xvbWJpYSxDT1ZJRF9EYXlfc2VyaWVzX0Nvc3RhUmljYSkKCmBgYAoKYGBge3J9CmR5Z3JhcGgoT3VyX0NvdW50cmllcywgbWFpbiA9ICJTQVJTLUNPVjItb3V0YnJlYWs6IFRvdGFsIGNhc2VzIGJ5IGNvdW50cnkiLCB4bGFiPSJEYXRlIiwgeWxhYj0iVG90YWwgY2FzZXMiLHdpZHRoID0gNzUwKSAlPiUgCiAgZHlTZXJpZXMoIkNPVklEX0RheV9zZXJpZXNfTGViYW5vbiIsICJMZWJhbm9uIixkcmF3UG9pbnRzID0gVFJVRSwgCiAgICAgICAgICAgcG9pbnRTaXplID0gMywgY29sb3I9cmdiKDAsMCwzLzI1NSkpICU+JSAKICBkeVNlcmllcygiQ09WSURfRGF5X3Nlcmllc19DaGlsZSIsICJDaGlsZSIsZHJhd1BvaW50cyA9IFRSVUUsIAogICAgICAgICAgIHBvaW50U2l6ZSA9IDMsY29sb3I9cmdiKDEyMC8yNTUsMjgvMjU1LDEwOS8yNTUpKSAlPiUgCiAgZHlTZXJpZXMoIkNPVklEX0RheV9zZXJpZXNfQ29sb21iaWEiLCAiQ29sb21iaWEiLGRyYXdQb2ludHMgPSBUUlVFLCAKICAgICAgICAgICBwb2ludFNpemUgPSAzLGNvbG9yPXJnYigyMzcvMjU1LDEwNS8yNTUsMzcvMjU1KSkgJT4lIAogIGR5U2VyaWVzKCJDT1ZJRF9EYXlfc2VyaWVzX0Nvc3RhUmljYSIsICJDb3N0YSBSaWNhIixkcmF3UG9pbnRzID0gVFJVRSwKICAgICAgICAgICBwb2ludFNpemUgPSAzLGNvbG9yPXJnYigyMDQvMjU1LDE5Ny8yNTUsMTI2LzI1NSkpICU+JSAKICBkeVJhbmdlU2VsZWN0b3IoKQpgYGAKCmBgYHtyfQpOZXdfTGViYW5vbjwtTmV3X2NvdW50KENPVklEXzJfRGF5X0xlYmFub24kV29ybGRfY29uZmlybWVkKQpOZXdfQ2hpbGU8LU5ld19jb3VudChDT1ZJRF8yX0RheV9DaGlsZSRXb3JsZF9jb25maXJtZWQpCk5ld19Db2xvbWJpYTwtTmV3X2NvdW50KENPVklEXzJfRGF5X0NvbG9tYmlhJFdvcmxkX2NvbmZpcm1lZCkKTmV3X0Nvc3RhUmljYTwtTmV3X2NvdW50KENPVklEXzJfRGF5X0Nvc3RhUmljYSRXb3JsZF9jb25maXJtZWQpCgpDT1ZJRF9OZXdfc2VyaWVzX0xlYmFub248LXh0cyhOZXdfTGViYW5vbiwgb3JkZXIuYnk9Q09WSURfMl9EYXlfTGViYW5vbiREYXRlMikKQ09WSURfTmV3X3Nlcmllc19DaGlsZTwteHRzKE5ld19DaGlsZSwgb3JkZXIuYnk9Q09WSURfMl9EYXlfQ2hpbGUkRGF0ZTIpCkNPVklEX05ld19zZXJpZXNfQ29sb21iaWE8LXh0cyhOZXdfQ29sb21iaWEsIG9yZGVyLmJ5PUNPVklEXzJfRGF5X0NvbG9tYmlhJERhdGUyKQpDT1ZJRF9OZXdfc2VyaWVzX0Nvc3RhUmljYTwteHRzKE5ld19Db3N0YVJpY2EsIG9yZGVyLmJ5PUNPVklEXzJfRGF5X0Nvc3RhUmljYSREYXRlMikKCk91cl9OZXdfQ291bnRyaWVzPC1jYmluZChDT1ZJRF9OZXdfc2VyaWVzX0xlYmFub24sQ09WSURfTmV3X3Nlcmllc19DaGlsZSxDT1ZJRF9OZXdfc2VyaWVzX0NvbG9tYmlhLENPVklEX05ld19zZXJpZXNfQ29zdGFSaWNhKQpgYGAKCmBgYHtyfQpkeWdyYXBoKE91cl9OZXdfQ291bnRyaWVzLCBtYWluID0gIlNBUlMtQ09WMi1vdXRicmVhazogTmV3IGNhc2VzIGJ5IGNvdW50cnkiLCB4bGFiPSJEYXRlIiwgeWxhYj0iVG90YWwgY2FzZXMiLHdpZHRoID0gNzUwKSAlPiUgCiAgZHlTZXJpZXMoIkNPVklEX05ld19zZXJpZXNfTGViYW5vbiIsICJMZWJhbm9uIixkcmF3UG9pbnRzID0gVFJVRSwgCiAgICAgICAgICAgcG9pbnRTaXplID0gMywgY29sb3I9cmdiKDAsMCwzLzI1NSkpICU+JSAKICBkeVNlcmllcygiQ09WSURfTmV3X3Nlcmllc19DaGlsZSIsICJDaGlsZSIsZHJhd1BvaW50cyA9IFRSVUUsIAogICAgICAgICAgIHBvaW50U2l6ZSA9IDMsY29sb3I9cmdiKDEyMC8yNTUsMjgvMjU1LDEwOS8yNTUpKSAlPiUgCiAgZHlTZXJpZXMoIkNPVklEX05ld19zZXJpZXNfQ29sb21iaWEiLCAiQ29sb21iaWEiLGRyYXdQb2ludHMgPSBUUlVFLCAKICAgICAgICAgICBwb2ludFNpemUgPSAzLGNvbG9yPXJnYigyMzcvMjU1LDEwNS8yNTUsMzcvMjU1KSkgJT4lIAogIGR5U2VyaWVzKCJDT1ZJRF9OZXdfc2VyaWVzX0Nvc3RhUmljYSIsICJDb3N0YSBSaWNhIixkcmF3UG9pbnRzID0gVFJVRSwKICAgICAgICAgICBwb2ludFNpemUgPSAzLGNvbG9yPXJnYigyMDQvMjU1LDE5Ny8yNTUsMTI2LzI1NSkpICU+JSAKICBkeVJhbmdlU2VsZWN0b3IoKQpgYGAKCiMgTG9va2luZyBmb3IgY29ycmVsYXRpb25zCgpgYGB7cn0KZmlnIDwtIHBsb3RfbHkoQ09WSURfdXBkYXRlZCwgeCA9IH5Db25maXJtZWQsIHkgPSB+RGVhdGhzLCB6ID0gflJlY292ZXJlZCwgd2lkdGg9NzUwKSAlPiUgCiAgYWRkX21hcmtlcnModGV4dD0gfkNvdW50cnkuUmVnaW9uICxob3ZlcmluZm89ICJ0ZXh0IiwKICAgICAgICAgICAgICBtYXJrZXIgPSBsaXN0KGNvbG9yPXJnYigxODkvMjU1LDU1LzI1NSw0OC8yNTUpKSkgJT4lIAogIGxheW91dCh0aXRsZT0iQ29uZmlybWVkIGNhc2VzIFZzLiBEZWF0aHMgVnMuIFJlY292ZXJlZCIsIHNjZW5lID0gbGlzdCgKICAgICAgICAgICAgICAgICAgICB4YXhpcyA9IGxpc3QodGl0bGUgPSAnQ29uZmlybWVkJyksCiAgICAgICAgICAgICAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICdEZWF0aHMnKSwKICAgICAgICAgICAgICAgICAgICAgemF4aXMgPSBsaXN0KHRpdGxlID0gJ1JlY292ZXJlZCcpKSkgCmZpZwpgYGAKCiMjIEh1bWFuIERldmVsb3BtZW50IEluZGV4CgpgYGB7cn0KSERJPC1yZWFkLmNzdigiSHVtYW4gRGV2ZWxvcG1lbnQgSW5kZXggKEhESSlfMi5jc3YiLHNlcD0iOyIsZGVjPSIsIikKYGBgCgpgYGB7cn0KQ09WSURfQ291bnRyeTwtQ09WSURfMiAlPiUgZmlsdGVyKERhdGUyPT1tYXgoRGF0ZTIpKSAlPiUgCiAgZ3JvdXBfYnkoQ291bnRyeS5SZWdpb24pICU+JSBzdW1tYXJpc2UoVG90YWxfY29uZmlybWVkPXN1bShDb25maXJtZWQpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRvdGFsX2RlYXRocz1zdW0oRGVhdGhzKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUb3RhbF9SZWNvdmVyZWQ9c3VtKFJlY292ZXJlZCkpCmBgYAoKUmVtb3ZlIGFmdGVyIHBhcmVudGhlc2VzOgpgYGB7cn0KSERJJENvdW50cnlfMjwtZ3N1YigiXFxzKlxcKFteXFwpXStcXCkiLCIiLGFzLmNoYXJhY3RlcihIREkkQ291bnRyeSkpCmBgYAoKYGBge3J9CkhESSRDb3VudHJ5XzJbSERJJENvdW50cnlfMj09IlVuaXRlZCBTdGF0ZXMiXTwtIlVTIgpIREkkQ291bnRyeV8yW0hESSRDb3VudHJ5XzI9PSJLb3JlYSJdPC0iU291dGggS29yZWEiCmBgYAoKUG9wdWxhdGlvbjoKYGBge3J9ClBvcHVsYXRpb248LXJlYWQuY3N2KCJXb3JsZF9wb3B1bGF0aW9uLmNzdiIsc2VwPSI7IixkZWM9IiwiKQpgYGAKClJlbW92ZSBhZnRlciBjb21tbWE6CmBgYHtyfQpQb3B1bGF0aW9uJENvdW50cnlfTmFtZV8yPC1nc3ViKCIsLioiLCAiIiwgYXMuY2hhcmFjdGVyKFBvcHVsYXRpb24kQ291bnRyeV9OYW1lKSkKYGBgCgpgYGB7cn0KUG9wdWxhdGlvbiRDb3VudHJ5X05hbWVfMltQb3B1bGF0aW9uJENvdW50cnlfTmFtZV8yPT0iVW5pdGVkIFN0YXRlcyJdPC0iVVMiClBvcHVsYXRpb24kQ291bnRyeV9OYW1lXzJbUG9wdWxhdGlvbiRDb3VudHJ5X0NvZGU9PSJLT1IiXTwtIlNvdXRoIEtvcmVhIgpQb3B1bGF0aW9uJENvdW50cnlfTmFtZV8yW1BvcHVsYXRpb24kQ291bnRyeV9Db2RlPT0iQ1pFIl08LSJDemVjaGlhIgpgYGAKCk5hdHVyYWwgSm9pbjoKYGBge3Isd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFfQpDT1ZJRF8zPC0gQ09WSURfQ291bnRyeSAlPiUgaW5uZXJfam9pbihIREksYnk9YygiQ291bnRyeS5SZWdpb24iPSJDb3VudHJ5XzIiKSkgJT4lIAogIGlubmVyX2pvaW4oUG9wdWxhdGlvbixieT1jKCJDb3VudHJ5LlJlZ2lvbiI9IkNvdW50cnlfTmFtZV8yIikpICU+JSAKICBzZWxlY3QoQ291bnRyeS5SZWdpb24sVG90YWxfY29uZmlybWVkLFRvdGFsX2RlYXRocyxUb3RhbF9SZWNvdmVyZWQsSERJX1JhbmtfMjAxOCxZZWFyXzIwMTgsCiAgICAgICAgIENvdW50cnlfQ29kZSxQb3B1bGF0aW9uXzIwMTgpICU+JSAKICBtdXRhdGUoQ2FzZXNfbWlsbGlvbj0oVG90YWxfY29uZmlybWVkL1BvcHVsYXRpb25fMjAxOCkqMTAwMDAwMCwKICAgICAgICAgUmVjb3ZlcmVkX3BlcmNlbnRhZ2U9KFRvdGFsX1JlY292ZXJlZC9Ub3RhbF9jb25maXJtZWQpKjEwMCkgIAoKQ09WSURfMzwtQ09WSURfM1shaXMubmEoQ09WSURfMyRQb3B1bGF0aW9uXzIwMTgpLF0KCmBgYAoKUGxvdCB0aGUgSHVtYW4gRGV2ZWxvcG1lbnQgSW5kZXgoSERJKSBWcy4gdGhlIG51bWJlciBvZiBjYXNlcyAoYXBwbHlpbmcgYSBsb2cgdHJhbnNmb3JtYXRpb24pLCBhbmQgdGhlIHByb3BvcnRpb24gb2YgcmVjb3ZlcmVkIGNhc2VzOgpgYGB7cn0KcGxvdDwtZ2dwbG90KGRhdGE9Q09WSURfMyxhZXMoeD1sb2coQ2FzZXNfbWlsbGlvbikseT1ZZWFyXzIwMTgsCiAgICAgICAgICAgICAgICAgICAgICAgIHNpemU9UmVjb3ZlcmVkX3BlcmNlbnRhZ2UsdGV4dD1Db3VudHJ5LlJlZ2lvbikpICsKICBnZW9tX3BvaW50KGNvbG9yPSJibGFjayIsZmlsbD1yZ2IoMjM3LzI1NSwxMDUvMjU1LDM3LzI1NSksc2hhcGU9MjEsYWxwaGE9MC42KSArCiAgc2NhbGVfc2l6ZShyYW5nZSA9IGMoMywxNSksIG5hbWU9IlJlY292ZXJlZCBcbiBwZXJjZW50YWdlIikgKwogIHRoZW1lX21pbmltYWwoKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0iYm90dG9tIikgKwogIGxhYnModGl0bGU9IkhESSBWcy4gbG9nYXJpdGhtdXMgb2YgQ09WSUQtMTkgY2FzZXMgYnkgbWlsbGlvbiBpbmhhYml0YW50cyBcbiBhbmQgcHJvcG9ydGlvbiBvZiByZWNvdmVyZWQiLAogICAgICAgeD0ibG4oQ2FzZXMvMU0gcG9wdWxhdGlvbikiLAogICAgICAgeT0iSERJIikKCmdncGxvdGx5KHBsb3QsdG9vbHRpcCA9IGMoInRleHQiKSx3aWR0aD03NTApCmBgYAoKCmBgYHtyfQpDT1ZJRF9udW1lcmljXzE8LUNPVklEXzMgJT4lIG11dGF0ZShMb2dfY2FzZXM9bG9nKENhc2VzX21pbGxpb24pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBEZWF0aF9wZXJjZW50YWdlPShUb3RhbF9kZWF0aHMvVG90YWxfY29uZmlybWVkKSoxMDApICU+JSAKICBzZWxlY3QoTG9nX2Nhc2VzLFJlY292ZXJlZF9wZXJjZW50YWdlLERlYXRoX3BlcmNlbnRhZ2UsWWVhcl8yMDE4KQoKY29ycnBsb3QoY29yKENPVklEX251bWVyaWNfMSksbWV0aG9kID0gIm51bWJlciIsdGwuY29sPSJibGFjayIsdGwuc3J0PTE1LAogICAgICAgICBjb2w9Y29sb3JSYW1wUGFsZXR0ZShjKHJnYigyMDQvMjU1LDE5Ny8yNTUsMTI2LzI1NSkscmdiKDIzNy8yNTUsMTA1LzI1NSwzNy8yNTUpKSkoMjAwKSkKYGBgCgojIyBJbmZhbnRzIGxhY2tpbmcgaW1tdW5pemF0aW9uLCBtZWFzbGVzICglIG9mIG9uZS15ZWFyLW9sZHMpCgpgYGB7cn0KTWVhc2xlczwtcmVhZC5jc3YoIk1lYXNsZXNfaW1tdW5pemF0aW9uLmNzdiIsc2VwPSI7IixkZWM9Ii4iKQpgYGAKCmBgYHtyfQpNZWFzbGVzJENvdW50cnlfMjwtZ3N1YigiXFxzKlxcKFteXFwpXStcXCkiLCIiLGFzLmNoYXJhY3RlcihNZWFzbGVzJENvdW50cnkpKQpgYGAKCmBgYHtyfQpNZWFzbGVzJENvdW50cnlfMltNZWFzbGVzJENvdW50cnlfMj09IlVuaXRlZCBTdGF0ZXMiXTwtIlVTIgpNZWFzbGVzJENvdW50cnlfMltNZWFzbGVzJENvdW50cnlfMj09IktvcmVhIl08LSJTb3V0aCBLb3JlYSIKYGBgCgoKYGBge3J9CkNPVklEXzM8LSBDT1ZJRF8zICU+JSBpbm5lcl9qb2luKE1lYXNsZXMsYnk9YygiQ291bnRyeS5SZWdpb24iPSJDb3VudHJ5XzIiKSkgJT4lIHNlbGVjdCgtYygiQ291bnRyeSIpKQpgYGAKCgpgYGB7cn0KZ2dwbG90KENPVklEXzMsIGFlcyh5PU1lYXNsZXNfMjAxOCkpICsgCiAgZ2VvbV9ib3hwbG90KGZpbGw9ImRvZGdlcmJsdWU0IixvdXRsaWVyLnNoYXBlID0gMjEsIAogICAgICAgICAgICAgICBvdXRsaWVyLmZpbGwgPSAiZmlyZWJyaWNrIixhbHBoYT0wLjc1KSArCiAgZ2d0aXRsZSgiQm94cGxvdCBvZiAlIGluZmFudHMgbGFja2luZyBtZWFzbGVzIGltbXVuaXphdGlvbiIpICsgeWxhYigiJSBvZiBpbmZhbnRzIikgKwogIHRoZW1lX21pbmltYWwoKQpgYGAKCmBgYHtyfQpnZ3Bsb3QoQ09WSURfMywgYWVzKE1lYXNsZXNfMjAxOCkpICsgCiAgZ2VvbV9oaXN0b2dyYW0oZmlsbD0iZG9kZ2VyYmx1ZTQiLGJpbnM9MjAsYWxwaGE9MC44KSArCiAgZ2d0aXRsZSgiSGlzdG9ncmFtIG9mICUgaW5mYW50cyBsYWNraW5nIG1lYXNsZXMgaW1tdW5pemF0aW9uIikgKyAKICB4bGFiKCIlIG9mIGluZmFudHMiKSArIAogIHlsYWIoIkNvdW50IikgKwogIHRoZW1lX21pbmltYWwoKQpgYGAKCmBgYHtyfQpwbG90PC1nZ3Bsb3QoZGF0YT1DT1ZJRF8zLGFlcyh4PWxvZyhDYXNlc19taWxsaW9uKSx5PU1lYXNsZXNfMjAxOCwKICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZT1SZWNvdmVyZWRfcGVyY2VudGFnZSx0ZXh0PUNvdW50cnkuUmVnaW9uKSkgKwogIGdlb21fcG9pbnQoY29sb3I9ImJsYWNrIixmaWxsPXJnYigxMjAvMjU1LDI4LzI1NSwxMDkvMjU1KSxzaGFwZT0yMSxhbHBoYT0wLjYpICsKICBzY2FsZV9zaXplKHJhbmdlID0gYygzLDE1KSwgbmFtZT0iUmVjb3ZlcmVkIFxuIHBlcmNlbnRhZ2UiKSArCiAgdGhlbWVfbWluaW1hbCgpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJib3R0b20iKSArCiAgbGFicyh0aXRsZT0iJSBpbmZhbnRzIGxhY2tpbmcgbWVhc2xlcyBpbW11bml6YXRpb24gVnMuIGxvZ2FyaXRobXVzIG9mIENPVklELTE5IGNhc2VzIGJ5IG1pbGxpb24gaW5oYWJpdGFudHMgXG4gYW5kIHByb3BvcnRpb24gb2YgcmVjb3ZlcmVkIiwKICAgICAgIHg9ImxuKENhc2VzLzFNIHBvcHVsYXRpb24pIiwKICAgICAgIHk9IiUgb2YgaW5mYW50cyIpCgpnZ3Bsb3RseShwbG90LHRvb2x0aXAgPSBjKCJ0ZXh0Iiksd2lkdGg9NzUwKQpgYGAKCiMjIEhlYWx0aCBleHBlbmRpdHVyZSAoJSBvZiBHRFApCgpgYGB7cn0KSGVhbHRoX2V4cGVuZGl0dXJlPC1yZWFkLmNzdigiSGVhbHRoX2V4cGVuZGl0dXJlX0dEUC5jc3YiLHNlcD0iOyIsZGVjPSIuIikKYGBgCgpgYGB7cn0KSGVhbHRoX2V4cGVuZGl0dXJlJENvdW50cnlfMjwtZ3N1YigiXFxzKlxcKFteXFwpXStcXCkiLCIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzLmNoYXJhY3RlcihIZWFsdGhfZXhwZW5kaXR1cmUkQ291bnRyeSkpCmBgYAoKYGBge3J9CkhlYWx0aF9leHBlbmRpdHVyZSRDb3VudHJ5XzJbSGVhbHRoX2V4cGVuZGl0dXJlJENvdW50cnlfMj09IlVuaXRlZCBTdGF0ZXMiXTwtIlVTIgpIZWFsdGhfZXhwZW5kaXR1cmUkQ291bnRyeV8yW0hlYWx0aF9leHBlbmRpdHVyZSRDb3VudHJ5XzI9PSJLb3JlYSJdPC0iU291dGggS29yZWEiCmBgYAoKCmBgYHtyfQpDT1ZJRF8zPC0gQ09WSURfMyAlPiUgaW5uZXJfam9pbihIZWFsdGhfZXhwZW5kaXR1cmUsYnk9YygiQ291bnRyeS5SZWdpb24iPSJDb3VudHJ5XzIiKSkgJT4lIHNlbGVjdCgtYygiQ291bnRyeSIpKQoKI3dyaXRlLmNzdihDT1ZJRF8zLCJDT1ZJRF9Db3ZhcmlhYmxlcy5jc3YiKQpgYGAKCmBgYHtyfQpwbG90PC1nZ3Bsb3QoZGF0YT1DT1ZJRF8zLGFlcyh4PWxvZyhDYXNlc19taWxsaW9uKSx5PUV4cGVuZGl0dXJlXzIwMTYsCiAgICAgICAgICAgICAgICAgICAgICAgIHNpemU9UmVjb3ZlcmVkX3BlcmNlbnRhZ2UsdGV4dD1Db3VudHJ5LlJlZ2lvbikpICsKICBnZW9tX3BvaW50KGNvbG9yPSJibGFjayIsZmlsbD1yZ2IoMjA0LzI1NSwxOTcvMjU1LDEyNi8yNTUpLHNoYXBlPTIxLGFscGhhPTAuNikgKwogIHNjYWxlX3NpemUocmFuZ2UgPSBjKDMsMTUpLCBuYW1lPSJSZWNvdmVyZWQgXG4gcGVyY2VudGFnZSIpICsKICB0aGVtZV9taW5pbWFsKCkgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb249ImJvdHRvbSIpICsKICBsYWJzKHRpdGxlPSJIZWFsdGggZXhwZW5kaXR1cmUgKCUgb2YgR0RQKSBWcy4gbG9nYXJpdGhtdXMgb2YgQ09WSUQtMTkgY2FzZXMgYnkgbWlsbGlvbiBpbmhhYml0YW50cyBcbiBhbmQgcHJvcG9ydGlvbiBvZiByZWNvdmVyZWQiLAogICAgICAgeD0ibG4oQ2FzZXMvMU0gcG9wdWxhdGlvbikiLAogICAgICAgeT0iJSBvZiBHRFAgaW4gaGVhbHRoIikKCmdncGxvdGx5KHBsb3QsdG9vbHRpcCA9IGMoInRleHQiKSx3aWR0aD03NTApCmBgYAoKCiMgRml0dGluZyBhIHJlZ3Jlc3Npb24gbW9kZWwKCmBgYHtyfQpNb2QxPC1sbShsb2coQ09WSURfMyRDYXNlc19taWxsaW9uKX5DT1ZJRF8zJFllYXJfMjAxOCtDT1ZJRF8zJE1lYXNsZXNfMjAxOCtDT1ZJRF8zJEV4cGVuZGl0dXJlXzIwMTYpCnN1bW1hcnkoTW9kMSkKYGBgCmBgYHtyfQpoaXN0KE1vZDEkcmVzaWR1YWxzKQpzaGFwaXJvLnRlc3QoTW9kMSRyZXNpZHVhbHMpCmBgYAoK